package com.york.jobmew.gateway.filter;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.google.gson.Gson;
import com.york.jobmew.gateway.constans.LoginConstants;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 登录过滤器
 * 过滤器和拦截器的意义不同，执行先后不同
 * <p>
 * 拦截器（Interceptor）
 * Spring MVC 特有 主要用于 Controller 层的横切逻辑（如权限校验、日志记录），与 Gateway 的过滤器无直接关联
 * 执行时机：无法干预底层网络通信，仅能处理已路由到 Spring MVC 的请求
 * <p>
 * 过滤器（GlobalFilter/GatewayFilter）
 * 执行顺序：通过 @Order 或 Ordered 接口控制优先级，数值越小优先级越高。例如，你的 LoginFilter 作为全局过滤器会作用于所有路由请求
 * 响应式编程模型：Spring Cloud Gateway 基于 Reactor 响应式编程，过滤器的执行通过 Mono 链式调用。
 * <p>
 * 例如，chain.filter(exchange) 会触发后续过滤器的订阅执行，而非立即执行
 */
@Component
@Slf4j
public class LoginFilter implements GlobalFilter {

    @Override
    @SneakyThrows
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        ServerHttpRequest.Builder mutate = request.mutate();
        String url = request.getURI().getPath();
        log.info("LoginFilter.filter.url:{}", url);

        // 1. pre 处理：检查路径、获取 Token
        if (url.equals("/user/doLogin"))
            // 放行登录接口
            return chain.filter(exchange);

        SaTokenInfo tokenInfo = StpUtil.getTokenInfo(); // 权限校验
        log.info("LoginFilter.filter.url:{}", new Gson().toJson(tokenInfo));
        String loginId = (String) tokenInfo.getLoginId();

        // 2. 修改请求头
        mutate.header(LoginConstants.LOGIN_ID, loginId);

        // 3. 继续执行后续过滤器链
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }

}
